#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sqlite3.h>
#include <signal.h>
#include <time.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/wait.h>
#include <sys/select.h>

#define  N  16
#define  R  1   //  user register
#define  L  2   //  user login
#define  Q  3   //  query word
#define  H  4   //  history record

#define DATABASE "my.db"
typedef struct{
	int type;
	char name[N];
	char data[256];   // password or word
}MSG;

void do_register(int connectfd, MSG *msg, sqlite3 *db);
void do_login(int connectfd, MSG *msg, sqlite3 *db);
void do_query(int connectfd, MSG *msg, sqlite3 *db);
void do_history(int connectfd, MSG *msg, sqlite3 *db);
int  do_searchword(int connectfd, MSG *msg);
void getdata(char *data);
int history_callback(void *arg, int f_num, char **f_value, char **f_name);

void handler(int sig)
{
    wait(NULL);
}

int main(int argc, char *argv[])
{
	if(argc != 3){
		printf("Usage : %s <ip> <port>\n", argv[0]);
		exit(-1);
	}
	sqlite3 *db = NULL;
	if(SQLITE_OK != sqlite3_open(DATABASE, &db)){
		printf("error : %s\n", sqlite3_errmsg(db));
		exit(-1);
	}
	int sockfd = 0;
	if(-1 == (sockfd = socket(AF_INET, SOCK_STREAM, 0))){
		perror("fail to socket");
		exit(-1);
	}
	
	struct sockaddr_in server_addr;
    memset(&server_addr, 0, sizeof(server_addr));
	server_addr.sin_family = AF_INET;
	server_addr.sin_addr.s_addr = inet_addr(argv[1]);
	server_addr.sin_port = htons(atoi(argv[2]));
	
    if(-1 == bind(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr))){
		perror("fail to bind");
		exit(-1);
	}
	
    if(-1 == listen(sockfd, 5)){
		perror("fail to listen");
		exit(-1);
	}

	int nbytes = 0;
	MSG msg;
	int i = 0;
	int ret = 0;
	int acceptfd = 0;
	fd_set readfds;
	FD_ZERO(&readfds);
	fd_set readfds_temp;
	FD_ZERO(&readfds_temp);
	FD_SET(sockfd, &readfds);
	int maxfd = 0;
	maxfd = maxfd > sockfd ? maxfd : sockfd;

    while(1){
		readfds_temp = readfds;
		if(-1 == (ret = select(maxfd+1, &readfds_temp, NULL, NULL, NULL))){
			perror("fail to select");
			exit(-1);
		}
		for(i = 0; i < maxfd+1; i++){
			if(FD_ISSET(i, &readfds_temp)){
				if(i == sockfd){
					if(-1 == (acceptfd = accept(i, NULL, NULL))){
						perror("fail to accept");
						exit(-1);
					}
					FD_SET(acceptfd, &readfds);
					maxfd = maxfd > acceptfd ? maxfd : acceptfd;
				}else{
					if(-1 == (nbytes = recv(i, &msg, sizeof(MSG), 0))){
						perror("fail to accept");
						exit(-1);
					}else if(0 == nbytes){
						FD_CLR(i, &readfds);
						close(i);
						printf("client quit\n");
						continue;
					}
					printf("type = [%d] data = [%s]\n", msg.type, msg.data);
					switch(msg.type)
					{
						case R:
							do_register(i, &msg, db);
							break;
						case L:
							do_login(i, &msg, db);
							break;
						case Q:
							do_query(i, &msg, db);
							break;
						case H:
							do_history(i, &msg, db);
							break;
					}
				}
				ret--;
			}
		}
	}
	return 0;
}

void do_register(int acceptfd, MSG *msg, sqlite3 *db){
}

void do_login(int acceptfd, MSG *msg, sqlite3 *db){
}

void do_query(int acceptfd, MSG *msg, sqlite3 *db){
}

void do_history(int acceptfd, MSG *msg, sqlite3 *db){
}
